home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 2 / Amiga Tools 2.iso / tools / packer / tar / src / diffarch.c < prev    next >
C/C++ Source or Header  |  1995-03-09  |  7KB  |  328 lines

  1. /*
  2.  * Diff files from a tar archive.
  3.  *
  4.  * Written 30 April 1987 by John Gilmore, ihnp4!hoptoad!gnu.
  5.  *
  6.  * @(#) diffarch.c 1.10 87/11/11 Public Domain - gnu
  7.  */
  8.  
  9. #include <stdio.h>
  10. #include <errno.h>
  11. #include <sys/types.h>
  12. #include <sys/stat.h>
  13.  
  14. #ifdef BSD42
  15. #include <sys/file.h>
  16. #endif
  17.  
  18. #ifdef USG
  19. #include <fcntl.h>
  20. #endif
  21.  
  22. /* Some systems don't have these #define's -- we fake it here. */
  23. #ifndef O_RDONLY
  24. #define    O_RDONLY    0
  25. #endif
  26. #ifndef    O_NDELAY
  27. #define    O_NDELAY    0
  28. #endif
  29.  
  30. extern int errno;            /* From libc.a */
  31. extern char *valloc();            /* From libc.a */
  32.  
  33. #include "tar.h"
  34. #include "port.h"
  35.  
  36. extern union record *head;        /* Points to current tape header */
  37. extern struct stat hstat;        /* Stat struct corresponding */
  38. extern int head_standard;        /* Tape header is in ANSI format */
  39.  
  40. extern void print_header();
  41. extern void skip_file();
  42.  
  43. char *filedata;                /* Pointer to area for reading
  44.                        file contents into */
  45.  
  46. /*
  47.  * Initialize for a diff operation
  48.  */
  49. diff_init()
  50. {
  51.  
  52.     /*NOSTRICT*/
  53.     filedata = (char *) valloc((unsigned)blocksize);
  54.     if (!filedata) {
  55.         fprintf(stderr,
  56.         "tar: could not allocate memory for diff buffer of %d bytes\n",
  57.             blocking);
  58.         exit(EX_ARGSBAD);
  59.     }
  60. }
  61.  
  62. /*
  63.  * Diff a file against the archive.
  64.  */
  65. void
  66. diff_archive()
  67. {
  68.     register char *data;
  69.     int fd, check, namelen, written;
  70.     int err, firsttime;
  71.     long size;
  72.     struct stat filestat;
  73.     char linkbuf[NAMSIZ+3];
  74.  
  75.     errno = EPIPE;            /* FIXME, remove perrors */
  76.  
  77.     saverec(&head);            /* Make sure it sticks around */
  78.     userec(head);            /* And go past it in the archive */
  79.     decode_header(head, &hstat, &head_standard, 1);    /* Snarf fields */
  80.  
  81.     /* Print the record from 'head' and 'hstat' */
  82.     if (f_verbose)
  83.         print_header(stdout);
  84.  
  85.     switch (head->header.linkflag) {
  86.  
  87.     default:
  88.         annofile(stderr, tar);
  89.         fprintf(stderr,
  90.            "Unknown file type '%c' for %s, diffed as normal file\n",
  91.             head->header.linkflag, head->header.name);
  92.         /* FALL THRU */
  93.  
  94.     case LF_OLDNORMAL:
  95.     case LF_NORMAL:
  96.     case LF_CONTIG:
  97.         /*
  98.          * Appears to be a file.
  99.          * See if it's really a directory.
  100.          */
  101.         namelen = strlen(head->header.name)-1;
  102.         if (head->header.name[namelen] == '/')
  103.             goto really_dir;
  104.  
  105.         fd = open(head->header.name, O_NDELAY|O_RDONLY);
  106.  
  107.         if (fd < 0) {
  108.             if (errno == ENOENT) {
  109.                 /* Expected error -- to stdout */
  110.                 annofile(stdout, (char *)NULL);
  111.                 fprintf(stdout, "%s: does not exist\n",
  112.                     head->header.name);
  113.             } else {
  114.                 annofile(stderr, (char *)NULL);
  115.                 perror(head->header.name);
  116.             }
  117.             skip_file((long)hstat.st_size);
  118.             goto quit;
  119.         }
  120. #ifdef AMIGA
  121.         err = stat(head->header.name, &filestat);
  122. #else
  123.         err = fstat(fd, &filestat);
  124. #endif
  125.         if (err < 0) {
  126.             annofile(stdout, (char *)NULL);
  127.             fprintf(stdout, "Cannot fstat file ");
  128.             perror(head->header.name);
  129.             skip_file((long)hstat.st_size);
  130.             goto qclose;
  131.         }
  132.  
  133.         if ((filestat.st_mode & S_IFMT) != S_IFREG) {
  134.             annofile(stdout, (char *)NULL);
  135.             fprintf(stdout, "%s: not a regular file\n",
  136.                 head->header.name);
  137.             skip_file((long)hstat.st_size);
  138.             goto qclose;
  139.         }
  140.  
  141.         filestat.st_mode &= ~S_IFMT;
  142.         if (filestat.st_mode != hstat.st_mode)
  143.             sigh("mode");
  144.         if (filestat.st_uid  != hstat.st_uid)
  145.             sigh("uid");
  146.         if (filestat.st_gid  != hstat.st_gid)
  147.             sigh("gid");
  148.         if (filestat.st_size != hstat.st_size) {
  149.             sigh("size");
  150.             skip_file((long)hstat.st_size);
  151.             goto qclose;
  152.         }
  153.         if (filestat.st_mtime != hstat.st_mtime)
  154.             sigh("mod time");
  155.  
  156.         firsttime = 0;
  157.  
  158.         for (size = hstat.st_size;
  159.              size > 0;
  160.              size -= written) {
  161.             /*
  162.              * Locate data, determine max length
  163.              * writeable, write it, record that
  164.              * we have used the data, then check
  165.              * if the write worked.
  166.              */
  167.             data = findrec()->charptr;
  168.             if (data == NULL) {    /* Check it... */
  169.                 annorec(stderr, tar);
  170.                 fprintf(stderr, "Unexpected EOF on archive file\n");
  171.                 break;
  172.             }
  173.             written = endofrecs()->charptr - data;
  174.             if (written > size) written = size;
  175.             errno = 0;
  176.             check = read (fd, filedata, written);
  177.             /*
  178.              * The following is in violation of strict
  179.              * typing, since the arg to userec
  180.              * should be a struct rec *.  FIXME.
  181.              */
  182.             userec(data + written - 1);
  183.             if (check == written) {
  184.                 /* The read worked, now compare the data */
  185.                 if (bcmp(data, filedata, check) == 0)
  186.                     continue;    /* It compares */
  187.                 if (firsttime++) {
  188.                     annofile(stdout, (char *)NULL);
  189.                     fprintf(stdout, "%s: data differs\n",
  190.                         head->header.name);
  191.                 }
  192.             }
  193.  
  194.             /*
  195.              * Error in reading from file.
  196.              * Print it, skip to next file in archive.
  197.              */
  198.             annofile(stderr, tar);
  199.             fprintf(stderr,
  200.     "Tried to read %d bytes from file, could only read %d:\n",
  201.                 written, check);
  202.             perror(head->header.name);
  203.             skip_file((long)(size - written));
  204.             break;    /* Still do the close, mod time, chmod, etc */
  205.         }
  206.  
  207.     qclose:
  208.         check = close(fd);
  209.         if (check < 0) {
  210.             annofile(stderr, tar);
  211.             fprintf(stderr, "Error while closing ");
  212.             perror(head->header.name);
  213.         }
  214.         
  215.     quit:
  216.         break;
  217.  
  218.     case LF_LINK:
  219.         check = 1;    /* FIXME deal with this */
  220.         /* check = link (head->header.linkname,
  221.                   head->header.name); */
  222.         /* FIXME, don't worry uid, gid, etc... */
  223.         if (check == 0)
  224.             break;
  225.         annofile(stderr, tar);
  226.         fprintf(stderr, "Could not link %s to ",
  227.             head->header.name);
  228.         perror(head->header.linkname);
  229.         break;
  230.  
  231. #ifdef S_IFLNK
  232.     case LF_SYMLINK:
  233.         check = readlink(head->header.name, linkbuf,
  234.                  (sizeof linkbuf)-1);
  235.         
  236.         if (check < 0) {
  237.             if (errno == ENOENT) {
  238.                 annofile(stdout, (char *)NULL);
  239.                 fprintf(stdout,
  240.                     "%s: no such file or directory\n",
  241.                     head->header.name);
  242.             } else {
  243.                 annofile(stderr, tar);
  244.                 fprintf(stderr, "Could not read link");
  245.                 perror(head->header.name);
  246.             }
  247.             break;
  248.         }
  249.  
  250.         linkbuf[check] = '\0';    /* Null-terminate it */
  251.         if (strncmp(head->header.linkname, linkbuf, check) != 0) {
  252.             annofile(stdout, (char *)NULL);
  253.             fprintf(stdout, "%s: symlink differs\n",
  254.                 head->header.linkname);
  255.         }
  256.         break;
  257. #endif
  258.  
  259.     case LF_CHR:
  260.         hstat.st_mode |= S_IFCHR;
  261.         goto make_node;
  262.  
  263. #ifdef S_IFBLK
  264.     /* If local system doesn't support block devices, use default case */
  265.     case LF_BLK:
  266.         hstat.st_mode |= S_IFBLK;
  267.         goto make_node;
  268. #endif
  269.  
  270. #ifdef S_IFIFO
  271.     /* If local system doesn't support FIFOs, use default case */
  272.     case LF_FIFO:
  273.         hstat.st_mode |= S_IFIFO;
  274.         hstat.st_rdev = 0;        /* FIXME, do we need this? */
  275.         goto make_node;
  276. #endif
  277.  
  278.     make_node:
  279.         /* FIXME, deal with umask */
  280.         
  281.         check = 1; /* FIXME, implement this */
  282.         /* check = mknod(head->header.name, (int) hstat.st_mode,
  283.             (int) hstat.st_rdev); */
  284.         if (check != 0) {
  285.             annofile(stderr, tar);
  286.             fprintf(stderr, "Could not make ");
  287.             perror(head->header.name);
  288.             break;
  289.         };
  290.         break;
  291.  
  292.     case LF_DIR:
  293.         /* Check for trailing / */
  294.         namelen = strlen(head->header.name)-1;
  295.     really_dir:
  296.         while (namelen && head->header.name[namelen] == '/')
  297.             head->header.name[namelen--] = '\0';    /* Zap / */
  298.         
  299.         check = 1; /* FIXME, implement this */
  300.         /* check = mkdir(head->header.name, 0300 | (int)hstat.st_mode); */
  301. #ifndef AMIGA
  302.         if (check != 0) {
  303.             annofile(stderr, tar);
  304.             fprintf(stderr, "Could not make directory ");
  305.             perror(head->header.name);
  306.             break;
  307.         }
  308. #endif        
  309.         break;
  310.  
  311.     }
  312.  
  313.     /* We don't need to save it any longer. */
  314.     saverec((union record **) 0);    /* Unsave it */
  315. }
  316.  
  317. /*
  318.  * Sigh about something that differs.
  319.  */
  320. sigh(what)
  321.     char *what;
  322. {
  323.  
  324.     annofile(stdout, (char *)NULL);
  325.     fprintf(stdout, "%s: %s differs\n",
  326.         head->header.name, what);
  327. }
  328.